package org.moon.framework.autoconfigure.openfeign.fallback;

import feign.FeignException;
import lombok.extern.slf4j.Slf4j;
import org.moon.framework.autoconfigure.MoonConstants;
import org.moon.framework.autoconfigure.springmvc.response.R;
import org.moon.framework.autoconfigure.utils.JsonUtils;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.util.*;

/**
 * 默认Feign Fallback
 * @author moon
 */
@Slf4j
public class MoonFeignFallback<T> implements MethodInterceptor {

    private final Class<T> targetType;
    private final String targetName;
    private final Throwable cause;

    public MoonFeignFallback(Class<T> targetType, String targetName, Throwable cause) {
        this.targetType = targetType;
        this.targetName = targetName;
        this.cause = cause;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        String errorMessage = cause.getMessage();
        log.error("MoonFeignFallback:[{}.{}] serviceId:[{}] message:[{}]", targetType.getName(), method.getName(), targetName, errorMessage);
        Class<?> returnType = method.getReturnType();
        // 集合类型反馈空集合
        if (List.class == returnType || Collection.class == returnType) {
            return Collections.emptyList();
        }
        if (Set.class == returnType) {
            return Collections.emptySet();
        }
        if (Map.class == returnType) {
            return Collections.emptyMap();
        }
        // 暂时不支持 Reactor，RxJava，异步等，返回值不是 R.class，直接返回 null。
        if (R.class != returnType) {
            return null;
        }
        // 非 FeignException，直接返回【600】请求被拒绝
        if (!(cause instanceof FeignException)) {
            return R.fail(MoonConstants.FEIGN.getCode(), errorMessage);
        }
        FeignException exception = (FeignException) cause;
        Optional<ByteBuffer> byteBuffer = exception.responseBody();
        // 如果返回的数据为空
        if (!byteBuffer.isPresent()) {
            return R.fail(MoonConstants.FEIGN.getCode(), errorMessage);
        }
        // 转换成 jsonNode 读取，因为直接转换，可能 对方放回的并 不是 ApiResult 的格式。
        R<String> str = JsonUtils.readAs(byteBuffer.get().array(),JsonUtils.getReference(String.class));
        return R.fail(str.getData());
    }

    @Override
    public int hashCode() {
        return Objects.hash(targetType);
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }

        if (null == obj || this.getClass() != obj.getClass()) {
            return false;
        }

        MoonFeignFallback<?> that = (MoonFeignFallback<?>) obj;

        return this.targetType.equals(that.targetType);
    }
}
